package de.bloxel;

import java.util.List;

import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.shadow.BasicShadowRenderer;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**
 * @author andreas
 */
public class Pong2 extends SimpleApplication {

	static float bLength = 0.1f;
	static float bWidth = 1.5f;
	static float bHeight = 0.1f;
	Material mat;
	Material mat2;
	Material mat3;
	BasicShadowRenderer bsr;
	private static final Sphere bullet;
	private static final Box brick;
	private static final SphereCollisionShape bulletCollisionShape;

	static {
		bullet = new Sphere(32, 32, 0.4f, true, false);
		bullet.setTextureMode(TextureMode.Projected);
		bulletCollisionShape = new SphereCollisionShape(0.4f);
		brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
		brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
	}

	public static void main(final String args[]) {
		new Pong2().start();
	}

	private BulletAppState bulletAppState;

	private final ActionListener actionListener = new ActionListener() {

		@Override
		public void onAction(final String name, final boolean keyPressed,
				final float tpf) {
			if (name.equals("shoot") && !keyPressed) {
				final Geometry bulletGeomentry = new Geometry("bullet", bullet);
				bulletGeomentry.setMaterial(mat2);
				bulletGeomentry.setShadowMode(ShadowMode.CastAndReceive);
				bulletGeomentry.setLocalTranslation(cam.getLocation());
				final RigidBodyControl bulletNode = new RigidBodyControl(
						bulletCollisionShape, 1);
				bulletNode.setLinearVelocity(cam.getDirection().mult(25));
				bulletGeomentry.addControl(bulletNode);
				rootNode.attachChild(bulletGeomentry);
				getPhysicsSpace().add(bulletNode);
			}
		}
	};

	private Node circleNode;

	private PhysicsSpace getPhysicsSpace() {
		return bulletAppState.getPhysicsSpace();
	}

	public void initArena() {
		final Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 10f);
		floorBox.scaleTextureCoordinates(new Vector2f(3, 6));

		final Geometry floor = new Geometry("floor", floorBox);
		floor.setMaterial(mat3);
		floor.setShadowMode(ShadowMode.Receive);
		floor.setLocalTranslation(0, -0.1f, 0);
		floor.addControl(new RigidBodyControl(new BoxCollisionShape(
				new Vector3f(10f, 0.1f, 10f)), 0));
		rootNode.attachChild(floor);
		getPhysicsSpace().add(floor);

		circleNode = new Node("circle");
		final float radius = 2f;
		for (float r = 0; r < Math.PI * radius; r += 0.2f) {
			final float x = (float) (Math.cos(r) * radius);
			final float y = (float) (Math.sin(r) * radius);
			final Vector3f pos = new Vector3f(x, y + 2 * radius, 0);
			final Geometry brickGeomentry = new Geometry("brick", brick);
			brickGeomentry.setMaterial(mat);
			brickGeomentry.setLocalTranslation(pos);
			brickGeomentry.addControl(new RigidBodyControl(r));
			brickGeomentry.setShadowMode(ShadowMode.CastAndReceive);
			brickGeomentry.getControl(RigidBodyControl.class).setFriction(0.6f);
			getPhysicsSpace().add(brickGeomentry);
			brickGeomentry.getControl(RigidBodyControl.class).setGravity(Vector3f.ZERO);
			brickGeomentry.getControl(RigidBodyControl.class).setKinematic(false);
			circleNode.attachChild(brickGeomentry);
		}
		rootNode.attachChild(circleNode);
	}

	protected void initCrossHairs() {
		guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
		final BitmapText ch = new BitmapText(guiFont, false);
		ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
		ch.setText("+"); // crosshairs
		ch.setLocalTranslation(
				// center
				settings.getWidth() / 2
				- guiFont.getCharSet().getRenderedSize() / 3 * 2,
				settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
		guiNode.attachChild(ch);
	}

	public void initMaterial() {
		mat = new Material(assetManager,
		"Common/MatDefs/Misc/SimpleTextured.j3md");
		final TextureKey key = new TextureKey(
		"Textures/Terrain/BrickWall/BrickWall.jpg");
		key.setGenerateMips(true);
		final Texture tex = assetManager.loadTexture(key);
		mat.setTexture("ColorMap", tex);

		mat2 = new Material(assetManager,
		"Common/MatDefs/Misc/SimpleTextured.j3md");
		final TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
		key2.setGenerateMips(true);
		final Texture tex2 = assetManager.loadTexture(key2);
		mat2.setTexture("ColorMap", tex2);

		mat3 = new Material(assetManager,
		"Common/MatDefs/Misc/SimpleTextured.j3md");
		final TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.png");
		key3.setGenerateMips(true);
		final Texture tex3 = assetManager.loadTexture(key3);
		tex3.setWrap(WrapMode.Repeat);
		mat3.setTexture("ColorMap", tex3);
	}

	@Override
	public void simpleInitApp() {
		bulletAppState = new BulletAppState();
		bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
		stateManager.attach(bulletAppState);
		initMaterial();
		initArena();
		initCrossHairs();
		cam.setLocation(new Vector3f(0, 6f, 6f));
		cam.lookAt(Vector3f.ZERO, new Vector3f(0, 1, 0));
		cam.setFrustumFar(30);
		inputManager.addMapping("shoot", new MouseButtonTrigger(
				MouseInput.BUTTON_LEFT));
		inputManager.addListener(actionListener, "shoot");

		rootNode.setShadowMode(ShadowMode.Off);
		bsr = new BasicShadowRenderer(assetManager, 256);
		bsr.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
		viewPort.addProcessor(bsr);
	}

	@Override
	public void simpleUpdate(final float tpf) {
		final List<Spatial> children = circleNode.getChildren();
		for (final Spatial spatial : children) {
			spatial.rotate(0,0,1.5f*tpf);
		}
		circleNode.rotate(0,0.2f * tpf, 0);
	}
}